using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Microsoft.EntityFrameworkCore.Storage;

namespace Microsoft.EntityFrameworkCore.Dm.Query.Internal;

public class DmQuerySqlGenerator : QuerySqlGenerator
{
	public DmQuerySqlGenerator(QuerySqlGeneratorDependencies dependencies)
		: base(dependencies)
	{
	}

	private bool HasStringChild(SqlBinaryExpression binaryExpression)
	{
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Expected O, but got Unknown
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Expected O, but got Unknown
		if (binaryExpression.Left != null && ((Expression)(object)binaryExpression.Left).Type == typeof(string))
		{
			return true;
		}
		if (binaryExpression.Right != null && ((Expression)(object)binaryExpression.Right).Type == typeof(string))
		{
			return true;
		}
		if (binaryExpression.Left != null && binaryExpression.Left is SqlBinaryExpression)
		{
			return HasStringChild((SqlBinaryExpression)binaryExpression.Left);
		}
		if (binaryExpression.Right != null && binaryExpression.Right is SqlBinaryExpression)
		{
			return HasStringChild((SqlBinaryExpression)binaryExpression.Right);
		}
		return false;
	}

	protected override string GetOperator(SqlBinaryExpression binaryExpression)
	{
		if (binaryExpression.OperatorType == ExpressionType.Add)
		{
			if (binaryExpression.Left.Type == typeof(string) || binaryExpression.Right.Type == typeof(string))
			{
				return "||";
			}
			if (binaryExpression.Left is SqlBinaryExpression && this.HasStringChild((SqlBinaryExpression)binaryExpression.Left))
			{
				return "||";
			}
			if (binaryExpression.Right is SqlBinaryExpression && this.HasStringChild((SqlBinaryExpression)binaryExpression.Right))
			{
				return "||";
			}
		}
		return base.GetOperator(binaryExpression);
	}

	protected override void GenerateTop(SelectExpression selectExpression)
	{
		if (selectExpression.Limit != null && selectExpression.Offset == null)
		{
			this.Sql.Append("TOP(");
			this.Visit(selectExpression.Limit);
			this.Sql.Append(") ");
		}
	}

	protected override void GenerateLimitOffset(SelectExpression selectExpression)
	{
		if (selectExpression.Offset != null)
		{
			this.Sql.AppendLine().Append("OFFSET ");
			this.Visit(selectExpression.Offset);
			this.Sql.Append(" ROWS");
			if (selectExpression.Limit != null)
			{
				this.Sql.Append(" FETCH NEXT ");
				this.Visit(selectExpression.Limit);
				this.Sql.Append(" ROWS ONLY");
			}
		}
	}

	protected override Expression VisitSqlFunction(SqlFunctionExpression sqlFunctionExpression)
	{
		if (sqlFunctionExpression.Name.StartsWith("@@", StringComparison.Ordinal))
		{
			this.Sql.Append(sqlFunctionExpression.Name);
			return sqlFunctionExpression;
		}
		if (sqlFunctionExpression.Name == "COUNT")
		{
			if (sqlFunctionExpression.Type == typeof(int))
			{
				this.Sql.Append(" CAST(");
				base.VisitSqlFunction(sqlFunctionExpression);
				this.Sql.Append(" AS INT) ");
				return sqlFunctionExpression;
			}
		}
		else if (sqlFunctionExpression.Name == "SUM")
		{
			if (sqlFunctionExpression.Type == typeof(int))
			{
				this.Sql.Append(" CAST(");
				base.VisitSqlFunction(sqlFunctionExpression);
				this.Sql.Append(" AS INT) ");
				return sqlFunctionExpression;
			}
		}
		else if ((sqlFunctionExpression.Name == "TRUNCATE" || sqlFunctionExpression.Name == "ROUND") && sqlFunctionExpression.Type == typeof(double))
		{
			this.Sql.Append(" CAST(");
			base.VisitSqlFunction(sqlFunctionExpression);
			this.Sql.Append(" AS DOUBLE)");
			return sqlFunctionExpression;
		}
		if (sqlFunctionExpression.Name.Equals("POSITION"))
		{
			this.Sql.Append("LOCATE");
			this.Sql.Append("(");
			this.GenerateList<SqlExpression>(sqlFunctionExpression.Arguments, delegate (SqlExpression e)
			{
				this.Visit(e);
			}, null);
			this.Sql.Append(")");
			return sqlFunctionExpression;
		}
		if (!sqlFunctionExpression.IsBuiltIn && string.IsNullOrEmpty(sqlFunctionExpression.Schema))
		{
			sqlFunctionExpression = new SqlFunctionExpression("SYSDBA", sqlFunctionExpression.Name, sqlFunctionExpression.Arguments, sqlFunctionExpression.IsNullable, sqlFunctionExpression.ArgumentsPropagateNullability, sqlFunctionExpression.Type, sqlFunctionExpression.TypeMapping);
		}
		return base.VisitSqlFunction(sqlFunctionExpression);
	}

	private static bool RequiresBrackets(SqlExpression expression)
	{
		if (!(expression is SqlBinaryExpression))
		{
			return expression is LikeExpression;
		}
		return true;
	}

	private void GenerateList<T>(IReadOnlyList<T> items, Action<T> generationAction, Action<IRelationalCommandBuilder> joinAction = null)
	{
		if (joinAction == null)
		{
			joinAction = delegate(IRelationalCommandBuilder isb)
			{
				isb.Append(", ");
			};
		}
		for (int i = 0; i < items.Count; i++)
		{
			if (i > 0)
			{
				joinAction(this.Sql);
			}
			generationAction(items[i]);
		}
	}

	protected override Expression VisitDelete(DeleteExpression deleteExpression)
	{
		SelectExpression selectExpression = deleteExpression.SelectExpression;
		if (selectExpression.Offset != null || selectExpression.Limit != null || selectExpression.Having != null || selectExpression.Orderings.Count != 0 || selectExpression.GroupBy.Count != 0 || selectExpression.Tables.Count != 1 || selectExpression.Tables[0] != deleteExpression.Table || selectExpression.Projection.Count != 0)
		{
			throw new InvalidOperationException(RelationalStrings.ExecuteOperationWithUnsupportedOperatorInSqlGeneration("ExecuteDelete"));
		}
		this.Sql.Append("DELETE FROM ");
		this.Visit(deleteExpression.Table);
		if (selectExpression.Predicate != null)
		{
			this.Sql.AppendLine().Append("WHERE ");
			SqlConstantExpression sqlConstantExpression = selectExpression.Predicate as SqlConstantExpression;
			if (sqlConstantExpression != null && sqlConstantExpression.Type == typeof(bool))
			{
				this.Sql.Append(((bool)sqlConstantExpression.Value) ? "TRUE " : "FALSE ");
			}
			else
			{
				this.Visit(selectExpression.Predicate);
			}
		}
		return deleteExpression;
	}
}
